package com.ease.util.logging {

   import com.ease.util.MixedUtil;
   import com.ease.util.StringUtils;

   import mx.core.mx_internal;
   import mx.logging.ILogger;
   import mx.logging.LogEvent;
   import mx.logging.LogEventLevel;
   import mx.logging.targets.LineFormattedTarget;
   import mx.utils.StringUtil;

   use namespace mx_internal;

   /**
    *  All logger target implementations that have a formatted line style output
    *  should extend this class. This class by itself does not log to any target; it is
    *  expected that subclasses will provide implementation of the <code>logMessage</code>
    *  method.
    *
    *  It provides default behavior for including date, time, category, class and level
    *  within the output by building on top of <code>LineFormattedTarget</code>.
    */

   public class LineFormattedTargetEx extends LineFormattedTarget {

      /**
       * Used to identify the stacktrace elements belonging to the logging classes.
       */
      private static const ERROR_PROLOG_PATTERN:RegExp = /.*mx\.logging::LogLogger.*?\s/s;

      /**
       * The level string in the formatted log string for unknwon levels.
       * See LogEvent.getLevelString.
       */
      private static const UNKNOWN_LEVEL_PATTERN:String = "[UNKNOWN]";

      private var _includeClass:Boolean;
      private var _lastEvent:LogEvent;

      /**
       * Whether to interpret the logger category as a qualified
       * class name, and displays only the simple class name.
       */
      public function get includeClass():Boolean {
         return _includeClass;
      }

      /** @private */
      public function set includeClass(value:Boolean):void {
         if (value) {
            // Set the parent includeCategory so that it is included in logEvent.
            this.includeCategory = value;
         }
         _includeClass = value;
      }

      /** @inheritDoc */
      public override function logEvent(event:LogEvent):void {
         if (!LogManager.isValidLevel(event.level)) {
            return;
         }
         // remember the event to be used later.
         _lastEvent = event;
         super.logEvent(event);
      }

      /**
       * Formats the message and calls the internalLog2 method to invoke the actual logging.
       */
      override mx_internal final function internalLog(message:String):void {
         message = formatMessage(message);
         logMessage(message, _lastEvent.level);
      }

      /**
       * @private Fix for the problem in the "AbstractTarget.removeLogger" function, which is
       * even if there are no Loggers attached, "_loggerCount--" is still executed.
       */
      public override function removeLogger(logger:ILogger):void {
         if (logger.hasEventListener(LogEvent.LOG)) {
            super.removeLogger(logger);
         }
      }

      /**
       *  Descendants of this class should override this method to direct the
       *  specified message to the desired output.
       *
       *  @param  message String containing preprocessed log message which may
       *              include time, date, category, etc. based on property settings,
       *              such as <code>includeDate</code>, <code>includeCategory</code>,
       *              <code>includeClass</code> etc.
       */
      protected function logMessage(message:String, level:int):void {
         // override this method to perform the redirection to the desired output
      }

      /**
       * Formats the message as per configurations of a particular logger. Will also append
       * the stacktrace to the message for any error event.
       */
      protected function formatMessage(message:String):String {
         if (_includeClass) {
            var category:String = ILogger(_lastEvent.target).category;
            message = message.replace(category,
               MixedUtil.getSimpleClassName(category) + ":");
         }
         var level:int = _lastEvent.level;
         var customLevelStr:String = LogManager.getCustomLevelString(level);
         if (customLevelStr != null) {
            if (this.includeLevel) {
               message = message.replace(UNKNOWN_LEVEL_PATTERN, "[" + customLevelStr + "]");
            }
         } else if (level >= LogEventLevel.ERROR) {
            // create a new stack trace
            var stacktrace:String = (new Error()).getStackTrace();
            if (!StringUtils.isNullorEmpty(stacktrace)) {
               // remove the prolog entries that are bogus and not pertinent to the error
               message += "\n" + stacktrace.replace(ERROR_PROLOG_PATTERN, "");
            }
         }
         return message;
      }

   }
}